﻿using System.Collections.Generic;
using System.Linq;
using DotNetNuke.ComponentModel;
using DotNetNuke.Entities.Users;
using DotNetNuke.Framework.Providers;
using DotNetNuke.UI.ControlPanels;

namespace BrandonHaynes.Providers.ControlPanel
    {
    /// <summary>
    /// Manages a set of control panel mappings (which are defined as 
    /// providers) and exposes a set of convenience methods.
    /// </summary>
    public class ControlPanelProvider
        {
        /// <summary>
        /// The name of the section that contains our control panel metadata
        /// </summary>
        public const string ControlPanelSectionName = "controlPanels";
        /// <summary>
        /// The key used to define the set of portals over which a mapping operates
        /// </summary>
        public const string PortalKey = "portals";
        /// <summary>
        /// The key used to define the set of roles over which a mapping applies
        /// </summary>
        public const string RoleKey = "roles";
         
        static ControlPanelProvider()
            {
            // Register our control panels with the provider container
            // We are utilizing transient instances, so control panels need not be immutable.
            ComponentFactory.InstallComponents(new ProviderInstaller(ControlPanelSectionName, typeof(ControlPanelBase), 
                                               ComponentLifeStyleType.Transient));   
            }

        private static IDictionary<string, ControlPanelMapping> _mappings;
        /// <summary>
        /// Exposes a dictionary of names to control panel mappings 
        /// </summary>
        public static IDictionary<string, ControlPanelMapping> Mappings
            {
            get
                {
                return _mappings ??
                    (_mappings = ProviderConfiguration
                        .GetProviderConfiguration(ControlPanelSectionName)
                        .Providers.Values
                        .Cast<Provider>()
                        .Select(provider =>
                                new ControlPanelMapping(provider.Name,
                                                     provider.Attributes.ToDictionary()))
                        .ToDictionary(settings => settings.Name, settings => settings));
                }
            }

        /// <summary>
        /// Given a mapping name, return the mapping metadata associated therewith
        /// </summary>
        public static ControlPanelBase GetControlPanel(string mappingName)
            { return ComponentFactory.GetComponent<ControlPanelBase>(mappingName); }

        /// <summary>
        /// Given a user, identify the set of control panel mappings that are:
        ///    (a) relevant to the portal with which the user is registered, and
        ///    (b) appropriate for the set of roles applied to that user
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public static IEnumerable<ControlPanelMapping> GetAuthorizedControlPanels(UserInfo user)
            {
            return Mappings
                    .Values
                    .Where(provider => IsAssignedToPortal(user.PortalID, provider))
                    .Where(provider => HasValidRoleForUser(user, provider));
            }

        private static bool IsAssignedToPortal(int portalId, ControlPanelMapping mapping)
            { return mapping.Portals.Contains(portalId); }

        private static bool HasValidRoleForUser(UserInfo user, ControlPanelMapping mapping)
            { return mapping.Roles.Any(user.IsInRole); }
        }
    }